// TempletPreviewWnd.cpp : implementation file
//

#include "stdafx.h"
#include "kwclientcore.h"
#include "TempletPreviewWnd.h"
#include "TempletPreviewPage.h"
#include "Client.h"

#include "CommonLib\Structure.h"

#include "MonitoringUnitLib\BaseCoalMineUnit.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

const int nLeftMargin = 10;
const int nUpperMargin = 10;
const int nRightMargin = 10;
const int nLowerMargin = 10;
const int nHScrollUnit = 40;
const int nVScrollUnit = 20;

/////////////////////////////////////////////////////////////////////////////
// CTempletPreviewWnd

CTempletPreviewWnd::CTempletPreviewWnd():
m_nTempletWidth(0),
m_nTempletHeight(0),
m_nHMax(0),
m_nVMax(0),
m_nHPos(0),
m_nVPos(0)
{
}

CTempletPreviewWnd::~CTempletPreviewWnd()
{
}


BEGIN_MESSAGE_MAP(CTempletPreviewWnd, CWnd)
	//{{AFX_MSG_MAP(CTempletPreviewWnd)
	ON_WM_PAINT()
	ON_WM_HSCROLL()
	ON_WM_VSCROLL()
	ON_WM_MOUSEWHEEL()
	ON_WM_LBUTTONDOWN()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CTempletPreviewWnd message handlers

void CTempletPreviewWnd::OnPaint() 
{
	CPaintDC dc(this); // device context for painting
	
	// TODO: Add your message handler code here
  ReportTempletHeader * pHeader = GetpReportTempletHeader();
  const std::vector<ReportField *>& ReportFields = GetReportFields();
  const std::vector<MonUnitItem *>& MonUnitItems = GetMonUnitItems();

  int x; 
  int y = nUpperMargin;

  CFont * pFont = new CFont;
  pFont->CreateFontIndirect(&pHeader->m_lfHead);
  CFont * pOldFont = dc.SelectObject(pFont);
  CSize size = dc.GetTextExtent(pHeader->m_szHeadText);
  x = (m_nTempletWidth-size.cx)/2;
  COLORREF crOldText = dc.SetTextColor(pHeader->m_crHeadFont);
  dc.TextOut(x-nHScrollUnit*m_nHPos, y-nVScrollUnit*m_nVPos, pHeader->m_szHeadText);
  TEXTMETRIC tm;
  dc.GetTextMetrics(&tm);
  y += tm.tmHeight+tm.tmExternalLeading;
  dc.SelectObject(pOldFont);
  delete pFont;

  pFont = new CFont;
  pFont->CreateFontIndirect(&pHeader->m_lfCell);
  pOldFont = dc.SelectObject(pFont);
  CString str = pHeader->GetTimeString();
  size = dc.GetTextExtent(str);
  x = m_nTempletWidth-nRightMargin-size.cx;
  dc.GetTextMetrics(&tm);
  y += tm.tmHeight+tm.tmExternalLeading;
  dc.SetTextColor(pHeader->m_crCellFont);
  dc.TextOut(x-nHScrollUnit*m_nHPos, y-nVScrollUnit*m_nVPos, str);
  y += tm.tmHeight+tm.tmExternalLeading;

  int oy = y;
  x = nLeftMargin;
  for (int i = 0;i < ReportFields.size();i++) 
  {
    ReportField * pReportField = ReportFields[i];
    y = oy;
    for (int j = 0;j < MonUnitItems.size()+1;j++) 
    {
      MonUnitItem * pMonUnitItem = j == 0?NULL:MonUnitItems[j-1];

      CRect rect(x, y, x+m_vecWidth[i]+1, y+m_vecHeight[j]+1);
      rect.OffsetRect(-m_nHPos*nHScrollUnit, -m_nVPos*nVScrollUnit);
      dc.FrameRect(&rect, CBrush::FromHandle((HBRUSH)GetStockObject(BLACK_BRUSH)));
      CString str = GetTempletItemString(i, j, pReportField, pMonUnitItem);
      if (!str.IsEmpty()) 
      {
        int cx;
        switch (pReportField->m_nColumnWidth)
        {
          case ReportField::MinWidth:cx = 2+1;break;
          case ReportField::SingleWidth:cx = tm.tmAveCharWidth*2+1;break;
          case ReportField::DoubleWidth:cx = tm.tmAveCharWidth*4+1;break;
          default:ASSERT(false);cx = 2+1;break;
        }
        int cy;
        switch (pHeader->m_nCellHeight)
        {
          case ReportField::MinHeight:cy = 1+1;break;
          case ReportField::SingleHeight:cy = (tm.tmHeight+tm.tmExternalLeading)/4+1;break;
          case ReportField::DoubleHeight:cy = (tm.tmHeight+tm.tmExternalLeading)/2+1;break;
          default:ASSERT(false);cy = 1+1;break;
        }
        rect.DeflateRect(cx, cy);
        UINT nAlignment;
        switch (pReportField->m_nAlignment)
        {
          case ReportField::AlignLeft:nAlignment = DT_LEFT;break;
          case ReportField::AlignCenter:nAlignment = DT_CENTER;break;
          case ReportField::AlignRight:nAlignment = DT_RIGHT;break;
          default:ASSERT(false);nAlignment = DT_LEFT;break;
        }
        dc.DrawText(str, &rect, DT_SINGLELINE | DT_VCENTER | nAlignment);
      }
      y += m_vecHeight[j];
    }
    x += m_vecWidth[i];
  }
  y += tm.tmHeight+tm.tmExternalLeading;

  dc.SelectObject(pOldFont);
  delete pFont;

  pFont = new CFont;
  pFont->CreateFontIndirect(&pHeader->m_lfFoot);
  pOldFont = dc.SelectObject(pFont);
  size = dc.GetTextExtent(pHeader->m_szFootText);
  x = nLeftMargin;
  dc.SetTextColor(pHeader->m_crFootFont);
  dc.TextOut(x-m_nHPos*nHScrollUnit, y-m_nVPos*nVScrollUnit, pHeader->m_szFootText);
  dc.SelectObject(pOldFont);
  delete pFont;

  dc.SetTextColor(crOldText);

	// Do not call CWnd::OnPaint() for painting messages
}

ReportTempletHeader * CTempletPreviewWnd::GetpReportTempletHeader() const
{
  return ((CTempletPreviewPage *)GetParent())->GetpReportTempletHeader();
}

const std::vector<ReportField *>& CTempletPreviewWnd::GetReportFields() const
{
  return ((CTempletPreviewPage *)GetParent())->GetReportFields();
}

const std::vector<MonUnitItem *>& CTempletPreviewWnd::GetMonUnitItems() const
{
  return ((CTempletPreviewPage *)GetParent())->GetMonUnitItems();
}

void CTempletPreviewWnd::ParamReady()
{
  CClientDC dc(this);

  m_nTempletWidth = CalcTempletWidth(dc);
  m_nTempletHeight = CalcTempletHeight(dc);

  CRect rect;
  GetClientRect(&rect);

  m_nVMax = max(0, (m_nTempletHeight-rect.Height()+nVScrollUnit-1)/nVScrollUnit);
  SetScrollRange(SB_VERT, 0, m_nVMax, false);
  m_nVPos = min(m_nVPos, m_nVMax);
  SetScrollPos(SB_VERT, m_nVPos);

  m_nHMax = max(0, (m_nTempletWidth-rect.Width()+nHScrollUnit-1)/nHScrollUnit);
  SetScrollRange(SB_HORZ, 0, m_nHMax, false);
  m_nHPos = min(m_nHPos, m_nHMax);
  SetScrollPos(SB_HORZ, m_nHPos);

  UpdateDisplay();
}

int CTempletPreviewWnd::CalcTempletWidth(CDC& dc)
{
  int nTableWidth = CalcTableWidth(dc);
  int nHeadWidth = CalcHeadWidth(dc);
  int nFootWidth = CalcFootWidth(dc);
  int nTimeWidth = CalcTimeWidth(dc);

  int nWidth = max(0, nTableWidth);
  nWidth = max(nWidth, nHeadWidth);
  nWidth = max(nWidth, nFootWidth);
  nWidth = max(nWidth, nTimeWidth);
  if (nWidth != 0) nWidth += nLeftMargin+nRightMargin;

  return nWidth;
}

int CTempletPreviewWnd::CalcTempletHeight(CDC& dc)
{
  int nTableHeight = CalcTableHeight(dc);
  int nHeadHeight = CalcHeadHeight(dc);
  int nFootHeight = CalcFootHeight(dc);
  int nTimeHeight = CalcTimeHeight(dc);

  int nHeight = nTableHeight+nHeadHeight+nFootHeight+nTimeHeight*4;
  if (nHeight != 0) nHeight += nUpperMargin+nLowerMargin;

  return nHeight;
}

int CTempletPreviewWnd::CalcTableWidth(CDC& dc)
{
  ReportTempletHeader * pHeader = GetpReportTempletHeader();
  const std::vector<ReportField *>& ReportFields = GetReportFields();
  const std::vector<MonUnitItem *>& MonUnitItems = GetMonUnitItems();

	CFont * pFont = new CFont;
	pFont->CreateFontIndirect(&pHeader->m_lfCell);
	CFont * pOldFont = dc.SelectObject(pFont);

	TEXTMETRIC tm;
	dc.GetTextMetrics(&tm);

  int nWidth = 0;
  m_vecWidth.clear();
  for (int i = 0;i < ReportFields.size();i++)
  {
    ReportField * pReportField = ReportFields[i];
    int w = 0;
    for (int j = 0;j < MonUnitItems.size()+1;j++)
    {
      MonUnitItem * pMonUnitItem = j == 0?NULL:MonUnitItems[j-1];
      CString str = GetTempletItemString(i, j, pReportField, pMonUnitItem, true);
      CSize size = dc.GetTextExtent(str);
      w = max(w, size.cx);
    }
    switch (pReportField->m_nColumnWidth)
    {
      case ReportField::MinWidth:w += 4+1;break;
      case ReportField::SingleWidth:w += tm.tmAveCharWidth*4+1;break;
      case ReportField::DoubleWidth:w += tm.tmAveCharWidth*8+1;break;
      default:ASSERT(false);w += 4+1;break;
    }
    m_vecWidth.push_back(w);
    nWidth += w;
  }
  nWidth++;

  dc.SelectObject(pOldFont);
  delete pFont;

  return nWidth;
}

int CTempletPreviewWnd::CalcHeadWidth(CDC& dc)
{
  ReportTempletHeader * pHeader = GetpReportTempletHeader();

  return CalcTextWidth(dc, pHeader->m_lfHead, pHeader->m_szHeadText);
}

int CTempletPreviewWnd::CalcFootWidth(CDC& dc)
{
  ReportTempletHeader * pHeader = GetpReportTempletHeader();

  return CalcTextWidth(dc, pHeader->m_lfFoot, pHeader->m_szFootText);
}

int CTempletPreviewWnd::CalcTimeWidth(CDC& dc)
{
  ReportTempletHeader * pHeader = GetpReportTempletHeader();

  return CalcTextWidth(dc, pHeader->m_lfCell, (LPCTSTR)pHeader->GetTimeString());
}

int CTempletPreviewWnd::CalcTextWidth(CDC& dc, const LOGFONT& lf, LPCTSTR lpszText)
{
  CFont * pFont = new CFont;
  pFont->CreateFontIndirect(&lf);
  CFont * pOldFont = dc.SelectObject(pFont);
  CSize size = dc.GetTextExtent(lpszText);
  dc.SelectObject(pOldFont);
  delete pFont;

  return size.cx;
}

int CTempletPreviewWnd::CalcTableHeight(CDC& dc)
{
  ReportTempletHeader * pHeader = GetpReportTempletHeader();
  const std::vector<MonUnitItem *>& MonUnitItems = GetMonUnitItems();

  CFont * pFont = new CFont;
  pFont->CreateFontIndirect(&pHeader->m_lfCell);
  CFont * pOldFont = dc.SelectObject(pFont);

  TEXTMETRIC tm;
  dc.GetTextMetrics(&tm);
  dc.SelectObject(pOldFont);
  delete pFont;

  int h;
  switch (pHeader->m_nCellHeight) 
  {
    case ReportField::MinHeight:h = 2+1;break;
    case ReportField::SingleHeight:h = (tm.tmHeight+tm.tmExternalLeading)/2+1;break;
    case ReportField::DoubleHeight:h = tm.tmHeight+tm.tmExternalLeading+1;break;
    default:ASSERT(false);h = 2+1;break;
  }

  m_vecHeight.clear();
  for (int i = 0;i < MonUnitItems.size()+1;i++) 
  {
    m_vecHeight.push_back(tm.tmHeight+tm.tmExternalLeading+h);
  }

  int nHeight = (tm.tmHeight+tm.tmExternalLeading+h)*(MonUnitItems.size()+1)+1;

  return nHeight;
}

int CTempletPreviewWnd::CalcHeadHeight(CDC& dc)
{
  ReportTempletHeader * pHeader = GetpReportTempletHeader();

  return CalcFontHeight(dc, pHeader->m_lfHead);
}

int CTempletPreviewWnd::CalcFootHeight(CDC& dc)
{
  ReportTempletHeader * pHeader = GetpReportTempletHeader();

  return CalcFontHeight(dc, pHeader->m_lfFoot);
}

int CTempletPreviewWnd::CalcTimeHeight(CDC& dc)
{
  ReportTempletHeader * pHeader = GetpReportTempletHeader();

  return CalcFontHeight(dc, pHeader->m_lfCell);
}

int CTempletPreviewWnd::CalcFontHeight(CDC& dc, const LOGFONT& lf)
{
	CFont * pFont = new CFont;
	pFont->CreateFontIndirect(&lf);
	CFont * pOldFont = dc.SelectObject(pFont);
	TEXTMETRIC tm;
	dc.GetTextMetrics(&tm);
	dc.SelectObject(pOldFont);
	delete pFont;

	return tm.tmHeight+tm.tmExternalLeading;
}

CString CTempletPreviewWnd::GetTempletItemString(int nCol, int nRow, ReportField * pReportField, MonUnitItem * pMonUnitItem, bool bPlaceHolder)
{
  CString str;

  if (nRow == 0) 
  {
    str = pReportField->m_szText;
  }
  else
  {
    switch (pReportField->m_nId)
    {
      case ReportField::CoalMineName:
        {
          BaseCoalMineUnit * pCoalMineUnit = Client::Instance()->GetCoalMineUnitById(pMonUnitItem->m_nCoalMineId);
          if (pCoalMineUnit) str = pCoalMineUnit->GetName();
          else str = "";
        }
        break;
      case ReportField::MonUnitId:
        str = pMonUnitItem->m_szMonUnitId;
        break;
      case ReportField::Comment:
        str = bPlaceHolder?"XXXXXXXXXXXXXXXX":"";
        break;
      default:
        str = "";
        break;
    }
  }

  return str;
}

void CTempletPreviewWnd::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
	// TODO: Add your message handler code here and/or call default
  CRect rect;
  GetClientRect(&rect);

  int nInc;
  switch (nSBCode) 
  {
    case SB_LEFT:nInc = -m_nHPos;break;
    case SB_RIGHT:nInc = m_nHMax-m_nHPos;break;
    case SB_LINELEFT:nInc = -1;break;
    case SB_LINERIGHT:nInc = 1;break;
    case SB_PAGELEFT:nInc = min(-1, -rect.Width()/nHScrollUnit);break;
    case SB_PAGERIGHT:nInc = max(1, rect.Width()/nHScrollUnit);break;
    case SB_THUMBPOSITION:
    case SB_THUMBTRACK:nInc = nPos-m_nHPos;break;
    default:nInc = 0;
  }

  int nOldPos = m_nHPos;
  m_nHPos += nInc;
  m_nHPos = max(0, min(m_nHPos, m_nHMax));
  if (m_nHPos != nOldPos)
  {
    SetScrollPos(SB_HORZ, m_nHPos);
    UpdateDisplay();
  }

	CWnd::OnHScroll(nSBCode, nPos, pScrollBar);
}

void CTempletPreviewWnd::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
	// TODO: Add your message handler code here and/or call default
  CRect rect;
  GetClientRect(&rect);

  int nInc;
  switch (nSBCode) 
  {
    case SB_TOP:nInc = -m_nVPos;break;
    case SB_BOTTOM:nInc = m_nVMax-m_nVPos;break;
    case SB_LINEUP:nInc = -1;break;
    case SB_LINEDOWN:nInc = 1;break;
    case SB_PAGEUP:nInc = min(-1, -rect.Height()/nVScrollUnit);break;
    case SB_PAGEDOWN:nInc = max(1, rect.Height()/nVScrollUnit);break;
    case SB_THUMBPOSITION:
    case SB_THUMBTRACK:nInc = nPos-m_nVPos;break;
    default:nInc = 0;
  }

  int nOldPos = m_nVPos;
  m_nVPos += nInc;
  m_nVPos = max(0, min(m_nVPos, m_nVMax));
  if (m_nVPos != nOldPos)
  {
    SetScrollPos(SB_VERT, m_nVPos);
    UpdateDisplay();
  }
	
	CWnd::OnVScroll(nSBCode, nPos, pScrollBar);
}

void CTempletPreviewWnd::UpdateDisplay()
{
  Invalidate();
  UpdateWindow();
}

BOOL CTempletPreviewWnd::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) 
{
	// TODO: Add your message handler code here and/or call default
  long lStyle = GetWindowLong(GetSafeHwnd(), GWL_STYLE);

  int nInc = -zDelta/WHEEL_DELTA;

  if (lStyle & WS_VSCROLL)
  {
    int nOldPos = m_nVPos;
    m_nVPos += nInc;
    m_nVPos = max(0, min(m_nVPos, m_nVMax));
    if (nOldPos != m_nVPos)
    {
      SetScrollPos(SB_VERT, m_nVPos);
      UpdateDisplay();
    }
  }
  else
  {
    if (lStyle & WS_HSCROLL)
    {
      int nOldPos = m_nHPos;
      m_nHPos += nInc;
      m_nHPos = max(0, min(m_nHPos, m_nHMax));
      if (nOldPos != m_nHPos)
      {
        SetScrollPos(SB_HORZ, m_nHPos);
        UpdateDisplay();
      }
    }
  }
	
	return CWnd::OnMouseWheel(nFlags, zDelta, pt);
}

void CTempletPreviewWnd::OnLButtonDown(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	SetFocus();

	CWnd::OnLButtonDown(nFlags, point);
}
